#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "includes/Mensajes.h"
#include "Estructuras.h"



/*******************************************************************************
* Funcion: enviarMensaje
* Tipo:  int
*-------------------------------------------------------------------------------
* Descripcion: La funcion recive por parametro el Socket al cual se le tiene que
*              enviar por TCP/IP el mensaje formateado. El Envio se hace por
*              medio de la funcion enviarInfo en un solo llamado.
*-------------------------------------------------------------------------------
* Retorno:     -1 : Indica que el mensje no se envio de forma correcta.
*               1 : El mensaje se envio de forma correcta
*******************************************************************************/
int enviarMensaje(int Socket, stMsgNIPC *mensaje)
{
	int retorno;
	stMsgNIPC cabecera;
	int size;

	int largoHeader = sizeof(cabecera.DescriptorID) +
			sizeof(cabecera.PayloadDescriptor) + sizeof(cabecera.PayloadLength);
	long largoTotal = largoHeader + mensaje->PayloadLength;


	if (mensaje->Payload == NULL)
	{
		memset(mensaje->PayloadLength, '\0',2);
	}
	else
	{
		size = strlen(mensaje->Payload);
		memcpy(mensaje->PayloadLength, mensaje->Payload, size);
	}

	// Armo la cabecera
	memcpy(cabecera.DescriptorID, mensaje->DescriptorID, 16);
	cabecera.PayloadDescriptor = mensaje->PayloadDescriptor;
	NumToBin(cabecera.PayloadLength, mensaje->PayloadLength);

	// Envio todo el mensaje junto.
    retorno = enviarInfo(Socket, &cabecera, largoHeader);
    retorno += enviarInfo(Socket, mensaje->Payload, mensaje->PayloadLength);
	if (retorno < largoTotal)
	{
		return -1;
	};

	return 1;
}

/*******************************************************************************
* Funcion: recibirMensaje
* Tipo F:  int
*-------------------------------------------------------------------------------
* Descripcion: La funcion recive por parametro el Socket del cual se le tiene
*              que recibir por TCP/IP el mensaje formateado. la recepcion se
*              hace por medio de la funcion recibirInfo en dos llamados. El
*              priemer llamado obtiene el header y el posterior llamado el
*              PayLoad, si fuese necesario.
*-------------------------------------------------------------------------------
* Retorno:     -1 : Indica que el mensje no se recibio de forma correcta.
*               1 : El mensaje se recibio de forma correcta
*******************************************************************************/
int recibirMensaje(int Socket, stMsgNIPC *mensaje)
{
	int retorno;
	stMsgNIPC cabecera;
    memset(mensaje->PayloadLength, "\0",2);
	int largoHeader = sizeof cabecera.DescriptorID +
			sizeof cabecera.PayloadDescriptor + sizeof cabecera.PayloadLength;

	// Recibo Primero el Header
	retorno = recibirInfo(Socket, &cabecera, largoHeader);
	if (retorno < largoHeader)
	{
		return -1;
	};

	// Desarmo la cabecera
	memcpy(mensaje->DescriptorID, cabecera.DescriptorID, 16);
	mensaje->PayloadDescriptor = cabecera.PayloadDescriptor;
	memcpy(mensaje->PayloadLength, BinToNum(cabecera.PayloadLength),
			cabecera.PayloadLength);

	// Si es necesario recibo Primero el PayLoad.
	if (mensaje->PayloadLength != 0)
	{
		mensaje->Payload = malloc(mensaje->PayloadLength+1);
                memset(mensaje->Payload, '\0', mensaje->PayloadLength+1);
		retorno = recibirInfo(Socket, mensaje->Payload, (mensaje->PayloadLength));
		if (retorno < mensaje->PayloadLength)
		{
			return -1;
		};
	}
	else
	{
		mensaje->Payload = NULL;
	}

	return 1;
}

/*******************************************************************************
* Funcion: recibirInfo
* Tipo F:  long
*-------------------------------------------------------------------------------
* Descripcion: La funcion recive por parametro el 'Socket' del cual se le tiene
*              que recibir por TCP/IP el la 'CantidadARecibir' y la guarda en el
*              'Buffer' indicado. En caso de no recibir la totalidad de
*              'CantidadARecibir' sigue recibiendo hasta que llegue a esa
*              cantidad o hasta que no haya mas datos en el Buffer del proceso.
*-------------------------------------------------------------------------------
* Retorno:     -1 : Indica que hubo un error de comunicacion.
*               x : Indica la cantidad de datos que finalmente se recibieron
*******************************************************************************/
int recibirInfo(int Socket, unsigned char *Buffer, long CantidadARecibir){
    long Recibido = 0;
    long TotalRecibido = 0;

    while(TotalRecibido < CantidadARecibir)
    {
		//Recibido = recv(Socket, Buffer+TotalRecibido, CantidadARecibir-TotalRecibido, 0);
                Recibido = recv(Socket, Buffer+TotalRecibido, CantidadARecibir-TotalRecibido, 0);
		switch(Recibido)
		{
			case 0:
				return TotalRecibido;
				break;

			case -1:
				return -1;
				break;

			default:
				TotalRecibido +=Recibido;
				break;
		}
    }

    return TotalRecibido;
}

/*******************************************************************************
* Funcion: recibirInfo
* Tipo F:  long
*-------------------------------------------------------------------------------
* Descripcion: La funcion recive por parametro el 'Socket' al cual se le tiene
*              que enviar por TCP/IP la 'CantidadAEnviar' de datos que estan en
*              el 'Buffer'. En caso de no recibir la totalidad de
*              'CantidadAEnviar' sigue enviando hasta que llegue a esa cantidad
*              o hasta que se produzca un error.
*-------------------------------------------------------------------------------
* Retorno:     -1 : Indica que hubo un error de comunicacion.
*               x : Indica la cantidad de datos que finalmente se enviaron
*******************************************************************************/
int enviarInfo(int Socket, unsigned char *Buffer, long CantidadAEnviar){
    long Enviados = 0;
    long TotalEnviados = 0;

    while (TotalEnviados < CantidadAEnviar)
    {
	Enviados = send(Socket, Buffer+TotalEnviados, CantidadAEnviar-TotalEnviados,0);
	switch (Enviados)
	{
		case 0:
			return TotalEnviados;
			break;

		case -1:
			return -1;
			break;

		default:
			TotalEnviados+=Enviados;
			break;
	}
    };

    return TotalEnviados;
}




/********************************************************************************************/
/**************************************************************************************/
unsigned int BinToNum (unsigned char * buffer)
{
	unsigned int total;

	total = buffer[0] + 256*buffer[1] + 65536*buffer[2] + 16777216*buffer[3];

	return total;
}

/**************************************************************************************/
void NumToBin (unsigned char * buffer, int total)
{

	if (total>16777216-1)
	{
		buffer[3]=total/16777216;
		total-=16777216;
	}
	else
	buffer[3]=0;

	if (total>65536-1)
	{
		buffer[2]=total/65536;
		total-=65536;
	}
	else
	buffer[2]=0;

	if (total>256-1)
	{
		buffer[1]=total/256;
		total-=256;
	}
	else
	buffer[1]=0;

	if (total>0)
	{
		buffer[0]=total;
		total-=0;
	}
	else
	buffer[0]=0;
}

/**************************************************************************************/

/*
 * @NOMBRE: armarPedidoFromMensaje
 * @DESC: 	completa la estructura stPedido a partir del mensaje NIPC recibido.
 * 			Devuelve el pedido por referencia.
 * */
int armarPedidoFromMensaje(stMsgNIPC* mensaje, stPedido* pedido)
{


	return EXIT_SUCCESS;
}

/*
 * @NOMBRE: armarMensajeFromPedido
 * @DESC: 	completa la estructura stMsgNIPC a partir del pedido recibido.
 * 			El mensaje es para enviarselo al PPD.
 * 			Devuelve el mensaje por referencia.
 * */
int armarMensajeFromPedido(stMsgNIPC* mensaje, stPedido* pedido)
{
	return EXIT_SUCCESS;
}
